/**
 * Copyright (c) 2015-2030 by Beijing Yanlight Co., Ltd.
 * All rights reserved.
 */
package com.yanlight.app.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.yanlight.app.dal.dao.*;
import com.yanlight.app.dal.dto.OrderQuery;
import com.yanlight.app.dal.dto.ShopMemberOpenidsQuery;
import com.yanlight.app.dal.dto.ShopMemberVagueQuery;
import com.yanlight.app.dal.entity.*;
import com.yanlight.app.model.OrderSpec;
import com.yanlight.app.request.AliDrawbackRequest;
import com.yanlight.app.request.OrderRequest;
import com.yanlight.app.request.WxDrawbackRequest;
import com.yanlight.app.response.OrderListResponse;
import com.yanlight.app.response.WxDrawbackResponse;
import com.yanlight.app.service.OrderService;
import com.yanlight.exception.ErrorType;
import com.yanlight.support.AliConstants;
import com.yanlight.support.ServletContextSupport;
import com.yanlight.support.WxConstants;
import com.yanlight.support.http.Response;
import com.yanlight.type.BooleanType;
import com.yanlight.type.OrderSceneType;
import com.yanlight.type.OrderType;
import com.yanlight.type.PayType;
import com.yanlight.util.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.util.*;

/**
 * @author haolw
 * @time 2017/08/28
 */
@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderDAO orderDAO;
    @Autowired
    private ShopMemberDAO shopMemberDAO;
    @Autowired
    private CompanyDAO companyDAO;

    @Autowired
    private AlipayConfigDAO alipayConfigDAO;

    @Autowired
    private DrawbackDAO drawbackDAO;


    @Override
    public OrderListResponse list(OrderRequest request) {
        OrderListResponse response = new OrderListResponse();
        response.setPageSize(request.getPageSize());
        response.setTotalRecord(0);

        String memberName = request.getMemberName();
        String memberPhone = request.getMemberPhone();
        String companyName = request.getCompanyName();
        OrderQuery condition = new OrderQuery();
        BeanUtils.copyProperties(request, condition);
        condition.setStatus(OrderType.PAYMENTED.getType());
        condition.setScenes(OrderSceneType.getMasterOffType());

        // 如果会员有模糊查询条件，处理会员查询，缓存部分条件数据，并标记为已查询
        List<String> memberOpenIds = new ArrayList<String>(16);
        Map<String, ShopMember> memberMap = new HashMap<String, ShopMember>(16);
        boolean memberVagueQuery = false;
        if (StringUtils.isNotEmpty(memberName) || StringUtils.isNotEmpty(memberPhone)) {
            ShopMemberVagueQuery vagueQuery = new ShopMemberVagueQuery();
            vagueQuery.setName(memberName);
            vagueQuery.setPhone(memberPhone);
            condition.setOpenIds(memberOpenIds);
            memberVagueQuery = true;
            List<ShopMember> members = shopMemberDAO.findVague(vagueQuery);
            if (CollectionUtils.isEmpty(members)) {
                return response;
            } else {
                for (ShopMember shopMember : members) {
                    String wxOpenid = shopMember.getWxOpenid();
                    String alipayUserid = shopMember.getAlipayUserid();
                    if (StringUtils.isNotBlank(wxOpenid)) {
                        memberOpenIds.add(wxOpenid);
                        memberMap.put(wxOpenid, shopMember);
                    }
                    if (StringUtils.isNotBlank(alipayUserid)) {
                        memberOpenIds.add(alipayUserid);
                        memberMap.put(alipayUserid, shopMember);
                    }
                }
            }
        }

        // 如果有公司模糊查询条件，处理，缓存，并标记
        List<Integer> companyIds = new ArrayList<Integer>(16);
        Map<Integer, Company> companyMap = new HashMap<Integer, Company>(16);
        boolean companyVagueQuery = false;
        if (StringUtils.isNotBlank(companyName)) {
            List<Company> companys = companyDAO.findByName(companyName);
            if (CollectionUtils.isEmpty(companys)) {
                return response;
            } else {
                condition.setCompanyIds(companyIds);
                companyVagueQuery = true;
                for (Company company : companys) {
                    Integer id = company.getId();
                    companyIds.add(id);
                    companyMap.put(id, company);
                }
            }
        }

        int count = orderDAO.count(condition);
        if (count > 0) {
            List<Order> orders = orderDAO.findList(condition);
            List<String> wxOpenids = new ArrayList<String>(16);
            List<String> alipayUserids = new ArrayList<String>(16);
            for (Order order : orders) {
                Integer payType = order.getPayType();
                String openId = order.getOpenId();
                Integer companyId = order.getCompanyId();
                if (PayType.WXPAY.getType().equals(payType)) {
                    if (!wxOpenids.contains(openId)) {
                        wxOpenids.add(openId);
                    }
                } else if (PayType.WXPAY.getType().equals(payType)) {
                    if (!alipayUserids.contains(openId)) {
                        alipayUserids.add(openId);
                    }
                }
                if (!companyIds.contains(companyId)) {
                    companyIds.add(companyId);
                }
            }

            // 没有会员条件模糊查询，查询出来的订单，需要关联会员信息，查询处理处理
            if (!memberVagueQuery) {
                ShopMemberOpenidsQuery query = new ShopMemberOpenidsQuery();
                query.setWxOpenids(wxOpenids);
                query.setAlipayUserids(alipayUserids);
                List<ShopMember> shopMembers = shopMemberDAO.findByOpenids(query);
                memberMap = new HashMap<>(shopMembers.size());
                for (ShopMember shopMember : shopMembers) {
                    String wxOpenid = shopMember.getWxOpenid();
                    String alipayUserid = shopMember.getAlipayUserid();
                    if (StringUtils.isNotBlank(wxOpenid)) {
                        memberMap.put(wxOpenid, shopMember);
                    }
                    if (StringUtils.isNotBlank(alipayUserid)) {
                        memberMap.put(alipayUserid, shopMember);
                    }
                }
            }

            // 没有公司条件模糊查询，查询出来的订单，需要关联公司信息，查询并处理
            if (!companyVagueQuery) {
                List<Company> companys = companyDAO.findByIds(companyIds);
                for (Company company : companys) {
                    Integer id = company.getId();
                    companyMap.put(id, company);
                }
            }

            OrderSpec spec;
            for (Order item : orders) {
                String openId = item.getOpenId();
                Integer companyId = item.getCompanyId();
                spec = new OrderSpec();
                BeanUtils.copyProperties(item, spec);
                ShopMember shopMember = memberMap.get(openId);
                if (shopMember != null) {
                    spec.setMemberPhone(shopMember.getName());
                    spec.setMemberName(shopMember.getPhone());
                }
                Company company = companyMap.get(companyId);
                if (company != null) {
                    spec.setCompanyName(company.getName());
                }

                if (item.getDrawbackId() == null || item.getDrawbackId() == 0) {
                    spec.setDrawback(false);
                } else {
                    spec.setDrawback(true);
                }

                response.addOrder(spec);
            }
        }
        response.setTotalRecord(count);
        return response;
    }

    @Override
    public void export(OutputStream outputStream, OrderRequest request) {
        request.setPage(BooleanType.FALSE.ordinal());
        OrderListResponse pageList = list(request);
        String templatePath = "/WEB-INF/excel_template/sys_order_template.xlsx";
        File file = ServletContextSupport.getContextFile(templatePath);
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);
            XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
            XSSFSheet sheet = workbook.getSheetAt(0);
            int count = pageList.getOrders().size();
            XSSFCellStyle cellStyle = workbook.createCellStyle();
            cellStyle.setAlignment(HorizontalAlignment.CENTER);
            for (int i = 0; i < count; i++) {
                OrderSpec orderSpec = pageList.getOrders().get(i);
                XSSFRow xssfRow = sheet.createRow(i + 1);
                XSSFCell xssfCell = xssfRow.createCell(0, CellType.NUMERIC);
                xssfCell.setCellValue(i + 1);
                xssfCell.setCellStyle(cellStyle);
                xssfCell = xssfRow.createCell(1, CellType.STRING);
                xssfCell.setCellValue(orderSpec.getSn());
                xssfCell.setCellStyle(cellStyle);
                xssfCell = xssfRow.createCell(2, CellType.STRING);
                xssfCell.setCellValue(orderSpec.getCompanyName());
                xssfCell.setCellStyle(cellStyle);
                xssfCell = xssfRow.createCell(3, CellType.STRING);
                xssfCell.setCellValue(orderSpec.getPayTime());
                xssfCell.setCellStyle(cellStyle);
                xssfCell = xssfRow.createCell(4, CellType.STRING);
                xssfCell.setCellValue(PayType.getNameByType(orderSpec.getPayType()));
                xssfCell.setCellStyle(cellStyle);
                xssfCell = xssfRow.createCell(5, CellType.STRING);
                xssfCell.setCellValue(orderSpec.getTotalFee());
                xssfCell.setCellStyle(cellStyle);
            }
            workbook.write(outputStream);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            try {
                inputStream.close();
                outputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return;

    }

    @Override
    public Response drawback(String orderId) {
        Order order = orderDAO.findByOrderId(orderId);
        if (order == null) {
            return ResponseUtil.fail(ErrorType.ORDER_NOT_EXIST);
        }
        Integer payType = order.getPayType();
        boolean drawbackStatus = false;
        switch (payType) {
            //支付宝
            case 1:
                drawbackStatus = aliDrawback(order);
                break;
            //微信
            case 2:
                drawbackStatus = wxDrawback(order);
                break;
            default:
                return ResponseUtil.fail(ErrorType.ORDER_ERROR);
        }

        if (drawbackStatus) {
            return ResponseUtil.success();
        } else {
            return ResponseUtil.fail(ErrorType.DRAWBACK_FAIL);
        }
    }

//    private boolean test() {
//        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", AliConstants.appId, AliConstants.privateKey, "json", "UTF-8", AliConstants.publicKey, "RSA2");
//        AlipaySystemOauthTokenRequest authRequest = new AlipaySystemOauthTokenRequest();
//        authRequest.setCode(authCode);
//        authRequest.setGrantType(AlipayConstants.AUTH_GRANTTYPE_CODE);
//        AlipaySystemOauthTokenResponse authResponse = alipayClient.execute(authRequest);
//    }

    private boolean aliDrawback(Order order) {
        String appID = AliConstants.appId;
        String privateKey = AliConstants.privateKey;
        String publicKey = AliConstants.publicKey;
        AlipayClient alipayClient = new DefaultAlipayClient(AliConstants.drawback, appID, privateKey, "JSON", "utf-8", publicKey, "RSA2");

        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();

        AliDrawbackRequest entity = new AliDrawbackRequest();
        entity.setOut_trade_no(order.getOutTradeNo());
        entity.setRefund_amount(order.getTotalFee());

        Integer companyId = order.getCompanyId();
        AlipayConfig alipayConfig = alipayConfigDAO.findByCompanyId(companyId);

        request.setBizContent(JSONObject.toJSONString(entity));
        try {
            AlipayTradeRefundResponse response = alipayClient.execute(request, null, alipayConfig.getAuthToken());
            if (response.isSuccess()) {
                updateDrawbackData(order.getId(), false);
                return true;
            } else {
                return false;
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return false;
        }
    }

    private boolean wxDrawback(Order order) {
        String nonceStr = RandomStringUtil.randomAlphanumeric(32);

        WxDrawbackRequest request = new WxDrawbackRequest();
        request.setAppid(WxConstants.appId);
        request.setMch_id(WxConstants.mchId);
        request.setSub_mch_id(order.getMchId());
        request.setNonce_str(nonceStr);
        request.setTransaction_id(order.getTransactionNo());
        request.setOut_trade_no(order.getOutTradeNo());

        String outRefundNo = RandomStringUtil.randomAlphanumeric(32);
        request.setOut_refund_no(outRefundNo);
        request.setOut_trade_no(order.getOutTradeNo());

        request.setRefund_fee((int) (order.getTotalFee() * 100));
        request.setTotal_fee((int) (order.getTotalFee() * 100));
        request.setRefund_desc("正常退款");
        request.setNotify_url(WxConstants.drawbackCallBack + order.getId());

        SortedMap<String, String> stringStringSortedMap = request.setupParams();
        String apiSignHMAC = SignatureUtil.createApiSign(stringStringSortedMap, WxConstants.apiKey);
        request.setSign(apiSignHMAC);

        String xmlFromObj = XmlParseUtil.getXmlFromObj(request);
        String result = WxHttpClientUtil.xmlPost(WxConstants.drawback, WxConstants.mchId, WxConstants.certPath, xmlFromObj);
        Map<String, String> stringStringMap = XmlUtil.xmlToMap(result);

        if (stringStringMap == null) {
            return false;
        }

        WxDrawbackResponse wxDrawbackResponse = null;
        try {
            wxDrawbackResponse = Map2BeanUtil.mapToObject(stringStringMap, WxDrawbackResponse.class);
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (wxDrawbackResponse == null) {
            return false;
        }

        //微信退款需要接口回执
        updateDrawbackData(order.getId(), false);
        return true;
    }

    private void updateDrawbackData(Integer orderId, boolean status) {
        Drawback drawback = new Drawback();
        drawback.setOrderId(orderId);
        drawback.setStatus(status);
        drawback.setDrawbackTime(DateTimeUtil.getNowTime());
        drawbackDAO.save(drawback);
        orderDAO.updateDrawbackStatus(orderId, drawback.getId());
    }
}
